
#include <compiler.h>

// 各子程序返回状态码
#define ERR_SUCCESS 0x00       // 操作成功
#define ERR_USB_CONNECT 0x15   /* 检测到USB设备连接事件,已经连接 */
#define ERR_USB_DISCON 0x16    /* 检测到USB设备断开事件,已经断开 */
#define ERR_USB_BUF_OVER 0x17  /* USB传输的数据有误或者数据太多缓冲区溢出 */
#define ERR_USB_DISK_ERR 0x1F  /* USB存储器操作失败,在初始化时可能是USB存储器不支持,在读写操作中可能是磁盘损坏或者已经断开 */
#define ERR_USB_TRANSFER 0x20  /* NAK/STALL等更多错误码在0x20~0x2F */
#define ERR_USB_UNSUPPORT 0xFB /*不支持的USB设备*/
#define ERR_USB_UNKNOWN 0xFE   /*设备操作出错*/
#define ERR_AOA_PROTOCOL 0x41  /*协议版本出错 */

/*USB设备相关信息表,CH554最多支持1个设备*/
#define ROOT_DEV_DISCONNECT 0
#define ROOT_DEV_CONNECTED 1
#define ROOT_DEV_FAILED 2
#define ROOT_DEV_SUCCESS 3
#define DEV_TYPE_KEYBOARD (USB_DEV_CLASS_HID | 0x20)
#define DEV_TYPE_MOUSE (USB_DEV_CLASS_HID | 0x30)
#define DEF_AOA_DEVICE 0xF0

/*
约定: USB设备地址分配规则(参考USB_DEVICE_ADDR)
地址值  设备位置
0x02    内置Root-HUB下的USB设备或外部HUB
0x1x    内置Root-HUB下的外部HUB的端口x下的USB设备,x为1~n
*/
#define HUB_MAX_PORTS 4
#define WAIT_USB_TOUT_200US 400 // 等待USB中断超时时间200uS@Fsys=12MHz

/* 数组大小定义 */
#define COM_BUF_SIZE 256 // 可根据最大描述符大小，动态修改以节省内存。

extern UINT8C SetupGetDevDescr[];  //*获取设备描述符*/
extern UINT8C SetupGetCfgDescr[];  //*获取配置描述符*/
extern UINT8C SetupSetAddr[];      //*设置USB地址*/
extern UINT8C SetupSetConfig[];    //*设置USB配置*/
extern UINT8C SetupSetInterface[]; //*设置USB接口配置*/
extern UINT8C SetupClrEndpStall[]; //*清除端点STALL*/
extern UINT8C SetupHIDGetDescr[];  //*获取HUB描述符*/
extern UINT8C SetupHIDSetIdle[];
extern UINT8C SetupHIDGetReportDescr[]; //*获取HID设备报表描述符*/
extern UINT8C SetupHIDGetProtocol[];    //*获取HID设备协议（启动协议或报表协议）*/
extern UINT8C SetupHIDSetReport[];      // 设置 SetReport
extern UINT8C XPrinterReport[];         //*打印机类命令*/
extern UINT8C GetProtocol[];            // AOA获取协议版本
extern UINT8C TouchAOAMode[];           // 启动配件模式
extern UINT8C Sendlen[];                /* AOA相关数组定义 */
extern UINT8C StringID[];               // 字符串ID,与手机APP相关的字符串信息
extern UINT8C SetStringID[];            // 应用索引字符串命令

typedef struct
{
    UINT8 DeviceStatus;              // 设备状态,0-无设备,1-有设备但尚未初始化,2-有设备但初始化枚举失败,3-有设备且初始化枚举成功
    UINT8 DeviceAddress;             // 设备被分配的USB地址
    UINT8 DeviceSpeed;               // 0为低速,非0为全速
    UINT8 DeviceType;                // 设备类型 (键盘或鼠标)
    UINT16 DeviceVID;                // 厂商标志
    UINT16 DevicePID;                // 产品标志
    UINT8 HIDDescriptorLength;       // HID设备的报表描述符长度（byte数）
    UINT8 HIDReportOffset;           // HID设备的报表忽略长度（bit数）——从这里开始是数据，前面是report id
    UINT8 HIDEndPoint;               // HID设备的IN端点
    UINT8 HIDbInterval;              // HID设备的中断传输时的轮询间隔（ms）
    volatile UINT8V HIDbIntervalCnt; // HID设备的中断传输时的轮询计数器
    UINT8 HIDbIfcNum;                // HID设备的有效接口号
    UINT8 UsbDevEndp0Size;           // USB设备的端点0的最大包尺寸
} _RootHubDev;
extern __xdata __at(0x0148) _RootHubDev ThisUsbDev;

extern UINT8 Set_Port;

extern __xdata __at(0x0000) UINT8V TxBuffer[256];  // USB发送数据缓存（必须是固定位置——不能在堆栈里）
extern __xdata __at(0x0040) UINT8V RxBuffer[256];  // USB接收数据缓存（必须是固定位置——不能在堆栈里）
extern __xdata __at(0x0200) UINT8 Com_Buffer[256]; // 接收报表、描述符，及发送指令的缓冲区
extern __xdata __at(0x0143) UINT8 Com_BufferLen;

extern __bit ps2_dev;
extern __bit FoundNewDev;
extern __bit keyboard_mode;

#define pSetupReq ((PXUSB_SETUP_REQ)TxBuffer)

void DisableRootHubPort();  // 关闭ROOT-HUB端口,实际上硬件已经自动关闭,此处只是清除一些结构状态
UINT8 AnalyzeRootHub(void); // 分析ROOT-HUB状态,处理ROOT-HUB端口的设备插拔事件
// 返回ERR_SUCCESS为没有情况,返回ERR_USB_CONNECT为检测到新连接,返回ERR_USB_DISCON为检测到断开
void SetHostUsbAddr(UINT8 addr);   // 设置USB主机当前操作的USB设备地址
void SetUsbSpeed(UINT8 FullSpeed); // 设置当前USB速度
void ResetRootHubPort();           // 检测到设备后,复位相应端口的总线,为枚举设备准备,设置为默认为全速
UINT8 EnableRootHubPort();         // 使能ROOT-HUB端口,相应的bUH_PORT_EN置1开启端口,设备断开可能导致返回失败
void SelectHubPort();              // 选择操作指定的ROOT-HUB端口
UINT8 WaitUSB_Interrupt(void);     // 等待USB中断
// CH554传输事务,输入目的端点地址/PID令牌,同步标志,以20uS为单位的NAK重试总时间(0则不重试,0xFFFF无限重试),返回0成功,超时/出错重试
UINT8 USBTransact();                                       // endp_pid: 高4位是token_pid令牌, 低4位是端点地址
UINT8 USBSetupstTransfer(PUINT8X DataBuf, PUINT8X RetLen); // 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区
// 如果需要接收和发送数据,那么DataBuf需指向有效缓冲区用于存放后续数据,实际成功收发的总长度返回保存在ReqLen指向的字节变量中
void CopySetupReqPkg(PUINT8C pReqPkt); // 复制控制传输的请求包
UINT8 CtrlGetDevDescr(void);           // 获取设备描述符,返回在TxBuffer中
UINT8 CtrlGetConfigDescr(void);        // 获取配置描述符,返回在TxBuffer中
UINT8 CtrlSetAddress(UINT8 addr);      // 设置USB设备地址
UINT8 CtrlSetConfig(UINT8 cfg);        // 设置USB设备配置
UINT8 CtrlClearEndpStall(UINT8 endp);  // 清除端点STALL

UINT8 CtrlSetIntercace(UINT8 cfg);                          // 设置USB设备接口
UINT8 CtrlHIDGetReportDescr();                              // HID类命令，GET_REPORT
void CtrlHIDSetIdle(UINT8 infc);                            // HID类命令，SET_IDLE
UINT8 AnalyzeCfgDescr(PUINT8X buf, UINT8 *cfg, UINT8 *ifc); // 从配置描述符中分析出HID中断端点的地址
UINT8 AnalyzeBulkEndp(PUINT8X buf);                         // 分析出批量端点
UINT8 EnumAllRootDevice(void);                              // 枚举所有ROOT-HUB端口的USB设备
UINT16 SearchTypeDevice(UINT8 type);                        // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号,输出端口号为0xFFFF则未搜索到
                                                            // 输出高8位为ROOT-HUB端口号,低8位为外部HUB的端口号,低8位为0则设备直接在ROOT-HUB端口上
UINT8 setReport(UINT8 val);

UINT8 InitRootDevice(void); // 初始化指定ROOT-HUB端口的USB设备
void InitUSB_Host(void);    // 初始化USB主机
